; 以下引导程序参考Microsoft FAT Specification设计
%include "Boot/BootProperty.S"
%include "Boot/DiskProperty.S"
; loader 在磁盘中的起始扇区
%define  LOADER_BEGIN_SECTOR (0x03) 
; 读磁盘操作允许重试5次
%define MAX_IO_FAILURE_TIMES (0x05) 
org MBR_BASE                      ; 用于定位到MBR
;; FAT文件系统引导扇区（512B）
jmp near MBR.ReadBootloaderFromDisk   ; BS_jmpBoot, 0 ~ 2
    db "SimpleOS"                     ; BS_OEMName, 3 ~ 10
    dw 0x200                          ; BPB_BytsPerSec, 11 ~ 12
    db 8                              ; BPB_SecPerClus, 13
    dw 8                              ; BPB_RsvdSecCnt
    db 2                              ; BPB_NumFATs
    dw 0                              ; BPB_RootEntCnt
    dw 0                              ; BPB_TotSec16
    db 0xf0                           ; BPB_Media
    dw 0                              ; BPB_FatSz16
    dw 18                             ; BPB_SecPerTrk
    dw 0                              ; BPB_NumHeads
    dd 0                              ; BPB_HiddSec
    dd (1 << 30) / (1 << 9)           ; BPB_TotSec32
;; FAT32 扩展 BPB 结构
    dd (1 << 11)                      ; BPB_FATSz32
    dw 0x00                           ; BPB_ExtFlags
    dw 0x00                           ; BPB_FSVer
    dd 2                              ; BPB_RootClus
    dw 1                              ; BPB_FSInfo
    dw 6                              ; BPB_BkBootSec
    times 12 db 0                     ; BPB_Reserved
    db 0x80                           ; BS_DrvNum
    db 0                              ; BS_Reserved1
    db 0x29                           ; BS_BootSig
    dd 05141632                       ; BS_VolID
    db "SimpleOS   "                  ; BS_VolLab
    db "FAT32   "                     ; BS_FilSysType
; 从磁盘中加载 bootloader 到内存中
%include "Boot/RealModeUtility/Print.asm"
bits 16
MBR.ReadBootloaderFromDisk:
    xor ax, ax
    mov ds, ax
MBR.ReadBootloaderFromDisk.Initialize:
    mov ax, LOADER_CODE_BASE >> 4
    mov es, ax ; 缓冲区段地址
    xor bx, bx ; 缓冲区偏移量
    xor dh, dh ; 磁头号 0
    mov dl, 0x80 ; 硬盘驱动器号
    xor ch, ch ; 起始柱面为 0 号
    mov cl, LOADER_BEGIN_SECTOR ; 下个待读入扇区为2号，1号扇区即MBR扇区
    xor si, si ; 读取当前扇区失败次数为0
    mov ss, bx
    mov sp, MBR_BASE
MBR.ReadBootloaderFromDisk.ReadSector:
    mov ah, 02 ; 读取磁盘功能
    mov al, 01 ; 读取一个扇区到缓冲区
    int 0x13
    jnc MBR.ReadBootloaderFromDisk.NextSector ; 操作成功，切换到下个扇区
    inc si ; 失败次数增1
    cmp si, MAX_IO_FAILURE_TIMES
    je MBR.ReadBootloaderFromDisk.Error
MBR.ReadBootloaderFromDisk.ResetDiskAndRetry:
    mov ah, 0x0d ; 复位磁盘
    int 0x13
    jmp MBR.ReadBootloaderFromDisk.ReadSector ; 重试读取扇区
MBR.ReadBootloaderFromDisk.NextSector:
    xor si, si ; 失败次数清零
    inc cl ; 下个待读取扇区
    mov ax, es
    add ax, SECTOR_SIZE >> 4
    mov es, ax ; 段后移512字节
    cmp cl, 7 ; 读取 3 ~ 6 扇区（CHS）
; MBR.ReadBootloaderFromDisk.NextSurface:
;     cmp cl, SECTORS_PER_TRACK ; 检查是否已经读完一张盘面
;     jbe MBR.ReadBootloaderFromDisk.ReadSector ; 继续读取当前盘面的扇区
;     inc dh ; 下个盘面
    ; mov cl, 1 ; 盘面起始扇区为1
; MBR.ReadBootloaderFromDisk.NextCylinder:
;     cmp dh, NUMBER_OF_HEADS ; 检查是否读完整个柱面
;     jb MBR.ReadBootloaderFromDisk.ReadSector ; 继续读取当前柱面的扇区
;     inc ch ; 下个柱面
;     xor dh, dh ; 回到0号磁头
;     cmp ch, 1 ; 暂时先读取一个柱面
    jb MBR.ReadBootloaderFromDisk.ReadSector ; 读取当前柱面的扇区
    call MBR.ReadBootloaderFromDisk.OK ; bootloader加载完毕
MBR.Boot:
    jmp LOADER_CODE_BASE
MBR.ReadBootloaderFromDisk.Error:
    push word 0b0000_1100
    push MBR.ReadBootloaderFromDisk.ERROR_MSG
    push word 0
    call Boot.RealModeUtility.Print
    add sp, 2 * 3
    ret
MBR.ReadBootloaderFromDisk.ERROR_MSG:
    db "[ERROR] Failed to read bootloader from disk.", 0x0d, 0x0a, 0x00
MBR.ReadBootloaderFromDisk.OK:
    push word 0b0000_1010
    push MBR.ReadBootloaderFromDisk.OK_MSG
    push word 0
    call Boot.RealModeUtility.Print
    add sp, 2 * 3
    ret
MBR.ReadBootloaderFromDisk.OK_MSG:
    db "[OK] Successfully read bootloader from disk.", 0x0d, 0x0a, 0x00
times (SECTOR_SIZE - ($ - $$) - 2)  db 0   ; ($ - $$)表示当前段已经写入的字节数，末尾两个字节固定
db 0x55, 0xaa ; Signature_word

; FSInfo
dd 0x41615252 ; FSI_LeadSig
times 480  db 0 ; FSI_Reserved1
dd 0x61417272 ; FSI_StructSig
dd 0xFFFFFFFF ; FSI_Free_Count
dd 0xFFFFFFFF ; FSI_NxtFree
times 12 db 0 ; FSI_Reserved2
dd 0XAA550000 ; FSI_TrailSig
